﻿namespace MatrixField
{
    using System;
    using System.Linq;

    public class MatrixFill
    {
        private const int MatrixSizeOfTwo = 2;
        private const int MatrixSizeOfFour = 4;

        public static void FillMatrix(Matrix matrix)
        {
            Direction direction = new Direction();
            direction.Row = 1;
            direction.Col = 1;
            direction.Name = DirectionName.DownRight;
            int maxValuecELL = matrix.Size * matrix.Size;

            while (true)
            {
                matrix[matrix.Row, matrix.Col] = matrix.ValueCell;
                if (matrix.ValueCell == maxValuecELL)
                {
                    break;
                }

                if (IsValidMove(matrix, direction))
                {
                    matrix.Row += direction.Row;
                    matrix.Col += direction.Col;
                    matrix.ValueCell++;
                }
                else
                {
                    if (direction.Name == DirectionName.Up && matrix.Row + direction.Row == 0 && matrix.Col + direction.Col == 0)
                    {
                        //// jump from left to right
                        matrix.Row = 0;
                        matrix.Col = 1;
                        direction.Name = DirectionName.Right;
                        direction.Row = 0;
                        direction.Col = 1;
                        matrix.ValueCell++;
                    }
                    else if (IsEmptyNeibour(matrix))
                    {
                        if (matrix.Size == MatrixSizeOfFour && matrix.ValueCell == maxValuecELL - 1)
                        {
                            matrix.ValueCell++;
                            matrix[2, 1] = matrix.ValueCell;
                            break;
                        }
                        else if (matrix.Size == MatrixSizeOfTwo && matrix.ValueCell == maxValuecELL - 1)
                        {
                            matrix.ValueCell++;
                            matrix[0, 1] = matrix.ValueCell;
                            break;
                        }

                        direction.ChangeDirection();
                        matrix.Row += direction.Row;
                        matrix.Col += direction.Col;
                        matrix.ValueCell++;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        private static bool IsValidMove(Matrix matrix, Direction direction)
        {
            bool isInRow = matrix.Row + direction.Row >= 0 && matrix.Row + direction.Row < matrix.Size;
            bool isInCol = matrix.Col + direction.Col >= 0 && matrix.Col + direction.Col < matrix.Size;
            bool isInMatrix = isInRow && isInCol;

            if (isInMatrix)
            {
                bool isEmptyNexCell = matrix[matrix.Row + direction.Row, matrix.Col + direction.Col] == 0;
                if (isEmptyNexCell)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        private static bool IsEmptyNeibour(Matrix matrix)
        {
            bool isEmptyNeibour = false;
            int i = matrix.Row;
            int j = matrix.Col;
            if (matrix.Row == 0 && matrix.Col == 0)
            {
                if (matrix[i + 1, j] == 0 ||
                    matrix[i, j + 1] == 0 ||
                    matrix[i + 1, j + 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Row == 0 && (matrix.Col > 0 && matrix.Col < matrix.Size))
            {
                if (matrix[i + 1, j] == 0 ||
                    matrix[i, j + 1] == 0 ||
                    matrix[i + 1, j + 1] == 0 ||
                    matrix[i + 1, j - 1] == 0 ||
                    matrix[i, j - 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Row == 0 && matrix.Col == matrix.Size - 1)
            {
                if (matrix[i + 1, j] == 0 ||
                    matrix[i + 1, j - 1] == 0 ||
                    matrix[i, j - 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Row == matrix.Size - 1 && matrix.Col == 0)
            {
                if (matrix[i - 1, j] == 0 ||
                    matrix[i - 1, j + 1] == 0 ||
                    matrix[i, j + 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Row == matrix.Size - 1 && matrix.Col == matrix.Size - 1)
            {
                if (matrix[i - 1, j] == 0 ||
                    matrix[i - 1, j - 1] == 0 ||
                    matrix[i, j - 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Row == matrix.Size - 1 && (matrix.Col > 0 && matrix.Col < matrix.Size))
            {
                if (matrix[i - 1, j] == 0 ||
                    matrix[i, j + 1] == 0 ||
                    matrix[i - 1, j + 1] == 0 ||
                    matrix[i - 1, j - 1] == 0 ||
                    matrix[i, j - 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Col == 0 && (matrix.Row > 0 && matrix.Row < matrix.Size))
            {
                if (matrix[i - 1, j] == 0 ||
                    matrix[i, j + 1] == 0 ||
                    matrix[i - 1, j + 1] == 0 ||
                    matrix[i + 1, j + 1] == 0 ||
                    matrix[i + 1, j] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else if (matrix.Col == matrix.Size - 1 && (matrix.Row > 0 && matrix.Row < matrix.Size))
            {
                if (matrix[i - 1, j] == 0 ||
                    matrix[i, j - 1] == 0 ||
                    matrix[i - 1, j - 1] == 0 ||
                    matrix[i + 1, j - 1] == 0 ||
                    matrix[i + 1, j] == 0)
                {
                    isEmptyNeibour = true;
                }
            }
            else
            {
                if (matrix[i - 1, j - 1] == 0 ||
                    matrix[i - 1, j] == 0 ||
                    matrix[i - 1, j + 1] == 0 ||
                    matrix[i + 1, j - 1] == 0 ||
                    matrix[i + 1, j] == 0 ||
                    matrix[i + 1, j + 1] == 0 ||
                    matrix[i, j - 1] == 0 ||
                    matrix[i, j + 1] == 0)
                {
                    isEmptyNeibour = true;
                }
            }

            return isEmptyNeibour;
        }
    }
}